#include "SocketIO.hpp"

#include <header.h>

namespace xww
{
    SocketIO::SocketIO(int fd)
        :_fd(fd)
    {
    }

    int SocketIO::readn(char *buf, int len)
    {
        int left = len;   // 表示还剩多少字节没有读取
        char *pbuf = buf; // 表示当前读取到的位置

        while (left > 0)
        {
            // recv的参数:fd,buf,len,flags
            // 分别是什么含义？
            // fd: 套接字描述符
            // buf: 存放接收到的数据的缓冲区
            // len: 要接收的字节数
            // flags: 额外的标志
            int ret = recv(_fd, pbuf, left, 0);//recv不是阻塞函数吗?//是的，recv是阻塞函数
            // Q:如果对端没有发送数据，是不是会阻塞？
            // 是的，如果对端没有发送数据，recv会阻塞直到有数据可读或者连接关闭
            // Q:那阻塞了还会走下面的if判断吗？
            // 是的，阻塞后会继续执行下面的if判断
            // Q:阻塞了为什么还往下走？没有往下走
            // 因为recv函数在有数据可读时会返回实际读取的字节数，
            // 如果没有数据可读，它会阻塞直到有数据可读或者连接关闭
            // 如果recv返回-1并且errno是EINTR，表示被信号中断了，
            // 这时会继续循环，重新调用recv函数尝试读取
            // 如果recv返回-1并且errno不是EINTR，表示发生了错误
            // 这时会打印错误信息并返回-1
            // 如果recv返回0，表示对端关闭了连接，这时会返回len - left，
            // 表示实际读取的字节数 
            if (ret == -1 && errno == EINTR)
            {
                continue; // 被信号中断,继续读取
            }
            else if (ret == -1)
            {
                perror("recv");
                return ret; //-1
            }
            else if (ret == 0) // 表示没有数据可读,对端关闭连接
            {
                // 对端关闭连接
                return len - left; // 返回实际读取的字节数
            }
            else // ret大于0,表示实际读取的字节数
            {
                left -= ret;
                pbuf += ret;
            }
        }
    }

    int SocketIO::sendn(const char *buff, int len)
    {
        int left = len;
        const char *pbuf = buff;
        while (left > 0)
        {
            int ret = send(_fd, pbuf, left, 0);
            if (ret < 0)
            {
                perror("Send");
                return ret; //-1
            }
            // 如果ret == 0,表示没有数据被发送
            // 这种情况一般不会发生，因为send函数在没有数据可发送时会阻塞
            else if (ret == 0)
            {
                // 发送失败,没有数据被发送
                return len - left; // 返回实际发送的字节数
            }
            // ret > 0,表示实际发送的字节数
            else if (ret > 0)
            {
                left -= ret;
                pbuf += ret; // 移动指针到下一个位置
                             // 继续发送剩余的数据
            }
        }
    }

    int SocketIO::readline(char *buf, int maxlen)
    {
        int left = maxlen - 1; // 表示还剩多少字节没有读取
                               //-1是为了给'\0'留出空间
        char *pbuf = buf; // 表示当前读取到的位置
        int total = 0;    // 表示读取的总的字节数
        while (left > 0)
        {
            int ret = recvPeek(buf,left);
            // 查找'\n'
            for (int i = 0; i < ret; ++i)
            {                
                // 找到了'\n'
                if (pbuf[i] == '\n')
                {
                    int number = i + 1;
                    ret = readn(pbuf,number);
                    total += ret; // 累加实际读取的字节数
                    pbuf[i] = '\0'; // 替换'\n'为'\0'
                    return total; // 返回总的字节数
                }
            }
        }
    }

    int SocketIO::recvPeek(char *buff, int maxlen) const
    {
        int ret = 0;
        do
        {
            ret = recv(_fd, buff, maxlen, MSG_PEEK);
        } while (ret == -1 && errno == EINTR);
        if (ret < 0)
        {
            perror("recvPeek");
        }
        return ret;
    }

    // int SocketIO::recvPeek(char *buf,int maxlen) const
    // {
    //     int ret = recv(_fd,buf,maxlen,MSG_PEEK);//MSG_PEEK标志表示只窥视数据
    //     if(ret == -1 && errno == EINTR)
    //     {
    //         //被信号中断,继续读取
    //         return recvPeek(buf,maxlen);
    //     }
    //     else if(ret == 0)
    //     {
    //         //表示没有数据可读,对端关闭连接
    //         return 0; // 返回0表示没有数据
    //     }
    //     else
    //     {
    //         return ret; // 返回实际读取的字节数
    //     }
    // }

} // end of namespace xww